package com.rgs.base.tasks.excel;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.io.Files;
import com.rgs.base.core.file.storage.FileStorageService;
import com.rgs.base.core.statics.CommonParamStaticClass;
import com.rgs.base.core.system.AsyncTaskStatusEnum;
import com.rgs.base.core.util.FileNameUtil;
import com.rgs.base.core.util.excel.ExcelUtil;
import com.rgs.base.core.util.excel.bo.ImportFileErrorBO;
import com.rgs.base.tasks.task.AsyncTaskHandle;
import com.rgs.base.tasks.task.AsyncTaskRunnableBO;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author Ren Gaoshuai
 * @date 2022-03-08 15:45
 **/
@Slf4j
public abstract class AbstractImportHandle<T>
        implements AsyncTaskHandle {


    private static final int BATCH_COUNT = 50;


    @Override
    public AsyncTaskRunnableBO execute(AsyncTaskRunnableBO asyncTaskRunnable) throws Exception {
        try {
            around(asyncTaskRunnable);
        } catch (Exception ex) {
            log.error("导入错误：{}", ex.getMessage());
            asyncTaskRunnable.setStatus(AsyncTaskStatusEnum.FAILED.getCode());
            asyncTaskRunnable.setFileName("");
            asyncTaskRunnable.setErrMassage(StrUtil.sub(ex.getMessage(), 0, 100));
        }
        return asyncTaskRunnable;
    }

    protected abstract List<T> preProcess(File tempDir,
                                          InputStream inputStream,
                                          AsyncTaskRunnableBO asyncTaskRunnable) throws IOException;

    protected abstract ImportFileErrorBO execute(T t, List<Object> objectList);

    protected abstract List<Object> initParameter(AsyncTaskRunnableBO asyncTaskRunnable);

    protected abstract FileStorageService getFileStorageService();

    protected void saveFileErr(List<ImportFileErrorBO> importFileErrorList,
                               WriteSheet writeSheet, ExcelWriter excelWriter) {

        ExcelUtil.writeExcel(writeSheet, excelWriter, importFileErrorList, ImportFileErrorBO.class);
    }

    /**
     * 模板方法
     *
     * @param asyncTaskRunnable
     * @return com.wxhj.common.core.task.AsyncTaskRunnableBO
     * @author daxiong
     * @date 2020/8/13 11:45 上午
     */
    public AsyncTaskRunnableBO around(AsyncTaskRunnableBO asyncTaskRunnable)
            throws Exception {
        AtomicLong errCount = new AtomicLong();
        String fileUuid = FileNameUtil.generateNameFile(CommonParamStaticClass.OFFICE_EXCEL_XLSX);
        File tempDir = Files.createTempDir();
        File errFile = new File(tempDir, fileUuid);
        InputStream fileInputStream =
                this.getFileStorageService().obtainFileForInputStream(asyncTaskRunnable.getFileName());
        WriteSheet writeSheet;
        ExcelWriter excelWriter;
        List<ImportFileErrorBO> importFileErrorList = new ArrayList<>();
        writeSheet = ExcelUtil.initWriteSheet(ImportFileErrorBO.class,
                asyncTaskRunnable.getTaskExplain());
        excelWriter = ExcelUtil.initExcelWriter(ImportFileErrorBO.class, errFile);
        try {
            List<Object> objectList = this.initParameter(asyncTaskRunnable);
            List<T> tList = preProcess(tempDir, fileInputStream, asyncTaskRunnable);
            tList.forEach(q -> {
                ImportFileErrorBO importFileErrorTemp = execute(q, objectList);
                if (importFileErrorTemp != null) {
                    importFileErrorList.add(importFileErrorTemp);
                }
                if (importFileErrorList.size() >= BATCH_COUNT) {
                    errCount.addAndGet(importFileErrorList.size());
                    saveFileErr(importFileErrorList, writeSheet, excelWriter);
                    importFileErrorList.clear();
                }
            });
            if (importFileErrorList.size() > 0) {
                errCount.addAndGet(importFileErrorList.size());
                saveFileErr(importFileErrorList, writeSheet, excelWriter);
                importFileErrorList.clear();

            }
        } catch (Exception ex) {
            throw ex;
        } finally {
            excelWriter.finish();
        }
        try {
            this.getFileStorageService().saveForInputStream(Files.asByteSource(errFile).openBufferedStream(), fileUuid);
            String fileName = asyncTaskRunnable.getTaskExplain() + "异常信息";

            if (errCount.get() == 0) {
                asyncTaskRunnable.setStatus(AsyncTaskStatusEnum.SUCCEED.getCode());

            } else {
                asyncTaskRunnable.setStatus(AsyncTaskStatusEnum.PART_SUCCEED.getCode());
            }
            //需要优化
            asyncTaskRunnable.setFileName(fileUuid);
            asyncTaskRunnable.setFileUrl(this.getFileStorageService()
                    .fileUrl(fileUuid, fileName, LocalDate.now()));
            asyncTaskRunnable.setErrMassage("失败" + errCount.get() + "个");
            return asyncTaskRunnable;
        } finally {
            tempDir.delete();
        }
    }


}
